﻿using System;
using System.Runtime.InteropServices;
using ActiveDirectoryUtilities.CommonLibrary.Unsafe;

namespace ActiveDirectoryUtilities.DirectoryServiceAccess
{
	public enum DomainControllerMode
	{
		Windows_2000 = 0,
		Windows_2003 = 2,
		Windows_2008 = 3
	}

	public class DomainController : IComparable, IComparable<DomainController>, IEquatable<DomainController>
	{
		internal enum InfoLevel : int
		{
			DS_DOMAIN_CONTROLLER_INFO_1 = 1,
			DS_DOMAIN_CONTROLLER_INFO_2 = 2
		}
		private string _netBiosName, _dnsHostName, _siteName, _siteObjectName, _computerObjectName, _serverObjectName, _ntdsDsaObjectName;
		private bool _fIsPdc, _fDsEnabled, _fIsGc;
		private Guid _siteObjectGuid, _computerObjectGuid, _serverObjectGuid, _ntdsDsaObjectGuid;

		/// <summary>
		/// Exposes the NetBIOS short name of the Domain Controller
		/// </summary>
		public string NetBiosName { get { return !string.IsNullOrEmpty(_netBiosName) ? _netBiosName.ToUpper() : string.Empty; } }
		/// <summary>
		/// Exposes the DNS host name of the Domain Controller.  If IsDsEnabled = false, this is always NULL.
		/// </summary>
		public string DnsHostName { get { return !string.IsNullOrEmpty(_dnsHostName) ? _dnsHostName.ToLower() : string.Empty; } }

		/// <summary>
		/// Provide a generic name property.  This will simplify the caller code so that a name will be return regardless of what dat we have about the system.
		///   If a specifically formatted name is desired, said name can be called separately
		/// </summary>
		public string Name
		{
			get
			{
				if (!string.IsNullOrEmpty(this.DnsHostName))
				{
					return this.DnsHostName;
				}
				else if (!string.IsNullOrEmpty(this.NetBiosName))
				{
					return this.NetBiosName;
				}
				throw new DirectoryServiceAccessException("Error retrieving Domain Controller name");
			}
		}

		/// <summary>
		/// Expose the site the Domain Controller resides in.  If IsDsEnabled = false, this is always NULL.
		/// </summary>
		public string SiteName { get { return _siteName; } }

		/// <summary>
		/// Expose the distinguished name of the site object the Domain Controller resides in.  If IsDsEnabled = false, this is always NULL.
		/// </summary>
		public string SiteObjectName { get { return _siteObjectName; } }

		/// <summary>
		/// Expose the distinguished name of the Domain Controller computer object.
		/// </summary>
		public string ComputerObjectName { get { return _computerObjectName; } }

		/// <summary>
		/// Expose the distinguished name of the server object in the configuration naming context that represents the Domain Controller.  If IsDsEnabled = false, this is always NULL.
		/// </summary>
		public string ServerObjectName { get { return _serverObjectName; } }

		/// <summary>
		/// Expose the NtDSA distinguished name under tje configuration naming context.  If IsDsEnabled = false, this is always NULL.
		/// </summary>
		public string NtdsDsaObjectName { get { return _ntdsDsaObjectName; } }

		/// <summary>
		/// True if the server is the PDC of the domain.
		/// </summary>
		public bool IsPdc { get { return _fIsPdc; } }

		/// <summary>
		/// True if this is running Active Directory.  False may indicate either an NT 4.0 DC or an incomplete set of data needed to run AD.  If the latter, these computer objects should probably be removed from AD.
		/// </summary>
		public bool IsDsEnabled { get { return _fDsEnabled; } }

		/// <summary>
		/// Is the box configured to be a GC.  This reports if the options attribute on the NtDSA object is OR'd with 0x1, not if the box is actually advertising as a GC.  If IsDsEnabled = false, this is always NULL.
		/// </summary>
		public bool IsGc { get { return _fIsGc; } }

		/// <summary>
		/// Exposes the GUID of the Domain Controller's site's AD object  If IsDsEnabled = false, this is always NULL.
		/// </summary>
		public Guid SiteObjectGuid { get { return _serverObjectGuid; } }

		/// <summary>
		/// Exposes the GUID of the Domain Controller's computer object
		/// </summary>
		public Guid ComputerObjectGuid { get { return _computerObjectGuid; } }

		/// <summary>
		/// Exposes the GUID of the Domain Controller's server object in the configuration NC  If IsDsEnabled = false, this is always NULL.
		/// </summary>
		public Guid ServerObjectGuid { get { return _serverObjectGuid; } }

		/// <summary>
		/// Exposes the GUID of the Domain Controller's NtDSA object.  If IsDsEnabled = false, this is always NULL.
		/// </summary>
		public Guid NtdsDsaObjectGuid { get { return _ntdsDsaObjectGuid; } }

		internal DomainController(NtDsApi.DS_DOMAIN_CONTROLLER_INFO_1 info)
		{
			_netBiosName = info.NetbiosName;
			_dnsHostName = info.DnsHostName;
			_siteName = info.SiteName;
			_computerObjectName = info.ComputerObjectName;
			_serverObjectName = info.ServerObjectName;
			_fIsPdc = info.fIsPdc;
			_fDsEnabled = info.fDsEnabled;
		}

		internal DomainController(NtDsApi.DS_DOMAIN_CONTROLLER_INFO_2 info)
		{
			_netBiosName = info.NetbiosName;
			_dnsHostName = info.DnsHostName;
			_siteName = info.SiteName;
			_siteObjectName = info.SiteObjectName;
			_computerObjectName = info.ComputerObjectName;
			_serverObjectName = info.ServerObjectName;
			_ntdsDsaObjectName = info.NtdsDsaObjectName;
			_fIsPdc = info.fIsPdc;
			_fDsEnabled = info.fDsEnabled;
			_fIsGc = info.fIsGc;
			_siteObjectGuid = info.SiteObjectGuid;
			_computerObjectGuid = info.ComputerObjectGuid;
			_serverObjectGuid = info.ServerObjectGuid;
			_ntdsDsaObjectGuid = info.NtdsDsaObjectGuid;
		}

		#region IComparable Members

		public int CompareTo(object obj)
		{
			if (obj is DomainController)
			{
				return string.Compare(this.Name, ((DomainController)obj).Name, StringComparison.OrdinalIgnoreCase);
			}

			return string.Compare(this.ToString(), obj.ToString(), StringComparison.OrdinalIgnoreCase);
		}

		public override string ToString()
		{
			return this.Name;
		}

		#endregion

		#region IComparable<DomainController> Members

		public int CompareTo(DomainController other)
		{
			return string.Compare(this.DnsHostName, other.DnsHostName, StringComparison.OrdinalIgnoreCase);
		}

		#endregion

		#region IEquatable<DomainController> Members

		public bool Equals(DomainController other)
		{
			if ((!string.IsNullOrEmpty(this.DnsHostName)) && (!string.IsNullOrEmpty(other.DnsHostName)))
			{
				return string.Compare(this.DnsHostName, other.DnsHostName, StringComparison.OrdinalIgnoreCase) == 0;
			}
			else if ((!string.IsNullOrEmpty(this.NetBiosName)) && (!string.IsNullOrEmpty(other.NetBiosName)))
			{
				return string.Compare(this.NetBiosName, other.NetBiosName, StringComparison.OrdinalIgnoreCase) == 0;
			}

			return false;
		}

		#endregion
	}
}